#include <string.h>

#include "list.h"

void
list_init(List *list, Disposer *disposer)
{
	list->len = 0;
	list->disposer = disposer;
	list->head = list->tail = NULL;
}

void
list_dispose(List *list)
{
	void *data;

	while(!list_remove(list, NULL, &data))
		if (list->disposer)
			list->disposer->dispose(data, list->disposer->extra);
}

Nit_error
list_add(List *list, List_entry *prev, const void *data)
{
	List_entry *entry = malloc(sizeof(*entry));

	if (!entry)
		return NIT_ERROR_MEMORY;

        entry->data = (void *) data;

	if (!prev) {
	        entry->next = list->head;
		list->head = entry;

		if (!list->tail)
			list->tail = entry;
	} else {
		entry->next = prev->next;
		prev->next = entry;

		if (!entry->next)
			list->tail = entry;
	}

	++list->len;
	return NIT_ERROR_FINE;
}

Nit_error
list_remove(List *list, List_entry *prev, void **data)
{
	List_entry *old_entry;

	if (!list->len)
		return NIT_ERROR_EMPTY;

	if (!prev) {
		*data = list->head->data;
		old_entry = list->head;
		list->head = list->head->next;

		if (list->len == 1)
			list->tail = NULL;
	} else {
		if (!prev->next)
			return NIT_ERROR_NO_NEXT;

		*data = prev->next->data;
		old_entry = prev->next;
		prev->next = prev->next->next;

		if (!prev->next)
			list->tail = prev;
	}

	free(old_entry);
	--list->len;
	return NIT_ERROR_FINE;
}

void **
list_peek(List *list)
{
	return list->head ? &list->head->data : NULL;
}
